package cn.lxb.web.starter.template.helper;

import cn.lxb.web.starter.template.provider.PdfAsianFontProvider;
import cn.lxb.web.starter.template.autoconfigure.config.ApplicationContextConfig;
import cn.lxb.web.starter.template.autoconfigure.properties.EasyPoiPrintPdfProperties;
import cn.lxb.web.starter.template.constant.PageDirection;
import cn.lxb.web.starter.template.constant.PageNumber;
import cn.lxb.web.starter.template.exception.ApplicationException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * PDF导出工具类
 *
 * @author zhoukui
 * @author 54lxb
 * @since 2019-11-20
 */
public class EasyPoiPdfHelper {

    /**
     * createPdf
     *
     * @param data        数据对象
     * @param properties  打印配置
     * @param pdfTemplate 模板
     * @param fileName    文件名称
     * @param response    response对象
     */
    public static void createPdf(Map<String, Object> data, EasyPoiPrintPdfProperties properties, String pdfTemplate, String fileName, HttpServletResponse response) throws ApplicationException {
        String htmlContent = freeMarkerRender(data, pdfTemplate);
        if (StringUtils.isBlank(htmlContent)) {
            throw new ApplicationException("模板解析出错");
        }
        try {
            Document document = new Document();
            // 设置文档方向，文档大小
            setPageSizeAndDirection(document, properties);
            // 设置浏览器响应头
            setPdfResponseHeader(fileName, response);
            // 输出文件
            writeFile(response, properties, document, htmlContent);
        } catch (IOException | DocumentException e) {
            e.printStackTrace();
            throw new ApplicationException("输出文件失败！");
        }
    }

    /**
     * createPortraitPdf
     *
     * @param data        数据对象
     * @param pdfTemplate 模板
     * @param fileName    文件名称
     * @param response    response对象
     */
    public static void createPortraitPdf(Map<String, Object> data, String pdfTemplate, String fileName, HttpServletResponse response) throws ApplicationException {
        EasyPoiPrintPdfProperties properties = EasyPoiPrintPdfProperties.defaultProperty();
        properties.setFontSize(null);
        properties.setPageDirection(PageDirection.PORTRAIT);
        createPdf(data, properties, pdfTemplate, fileName, response);
    }

    /**
     * createTransversePdf
     *
     * @param data        数据对象
     * @param pdfTemplate 模板
     * @param fileName    文件名称
     * @param response    response对象
     */
    public static void createTransversePdf(Map<String, Object> data, String pdfTemplate, String fileName, HttpServletResponse response) throws ApplicationException {
        EasyPoiPrintPdfProperties properties = EasyPoiPrintPdfProperties.defaultProperty();
        properties.setFontSize(null);
        properties.setPageDirection(PageDirection.TRANSVERSE);
        createPdf(data, properties, pdfTemplate, fileName, response);
    }

    /**
     * 设置PDF导出文件的响应头
     *
     * @param fileName 文件名字
     * @param response HttpServletResponse
     * @throws UnsupportedEncodingException 编码错误
     */
    public static void setPdfResponseHeader(String fileName, HttpServletResponse response) throws UnsupportedEncodingException {
        String charset = StandardCharsets.UTF_8.displayName();
        response.setCharacterEncoding(charset);
        response.setContentType(String.format("application/pdf;charset=%s", charset));
        response.setHeader("Content-type", String.format("application/pdf;charset=%s", charset));
        response.addHeader("Content-Disposition", String.format("filename=%s.pdf", URLEncoder.encode(fileName + System.currentTimeMillis(), charset)));
    }

    /**
     * 输出文件
     * @param response HttpServletResponse
     * @param properties 配置文件
     * @param document  Document
     * @param htmlContent 解析完了的模板内容
     * @throws IOException 文件写出问题
     * @throws DocumentException 文档问题
     */
    private static void writeFile(HttpServletResponse response, EasyPoiPrintPdfProperties properties, Document document, String htmlContent) throws IOException, DocumentException {
        // 设置字体大小
        PdfAsianFontProvider fontProvider = new PdfAsianFontProvider();
        if (properties.getFontSize() != null) {
            fontProvider.setFontSize(properties.getFontSize());
        }
        // 输出文件
        ServletOutputStream outputStream = response.getOutputStream();
        PdfWriter writer = PdfWriter.getInstance(document, outputStream);
        document.open();
        XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(htmlContent.getBytes()), null, StandardCharsets.UTF_8, fontProvider);
        document.close();
        writer.close();
        outputStream.flush();
        outputStream.close();
    }

    /**
     * 设置文档方向，文档大小
     *
     * @param document 文档
     * @param properties 文档配置信息
     */
    private static void setPageSizeAndDirection(Document document, EasyPoiPrintPdfProperties properties) {
        if (properties.getPageNumber().equals(PageNumber.A4)) {
            if (properties.getPageDirection().equals(PageDirection.TRANSVERSE)) {
                document.setPageSize(PageSize.A4.rotate());
            } else {
                document.setPageSize(PageSize.A4);
            }
        } else if (properties.getPageNumber().equals(PageNumber.B5)) {
            if (properties.getPageDirection().equals(PageDirection.TRANSVERSE)) {
                document.setPageSize(PageSize.B5.rotate());
            } else {
                document.setPageSize(PageSize.B5);
            }
        } else if (properties.getPageNumber().equals(PageNumber.CUSTOM)) {
            // 看到这里的同学请查看一下源码，不然不知道为什么
            com.itextpdf.awt.geom.Rectangle rectangle = new com.itextpdf.awt.geom.Rectangle();
            rectangle.height = properties.getPageCustom().getHeight().doubleValue();
            rectangle.width = properties.getPageCustom().getWidth().doubleValue();
            document.setPageSize(new Rectangle(rectangle));
        }
    }

    /**
     * 渲染
     *
     * @param data         数据对象
     * @param htmlTemplate html模板
     * @return 模板
     */
    private static String freeMarkerRender(Map<String, Object> data, String htmlTemplate) {
        Writer out = new StringWriter();
        try {
            // 获取模板,并设置编码方式
            ApplicationContext context = ApplicationContextConfig.getContext();
            Configuration freemarkerCfg = context.getBean(Configuration.class);
            Template template = freemarkerCfg.getTemplate(htmlTemplate,"UTF-8");
            // 合并数据模型与模板，将合并后的数据和模板写入到流中，这里使用的字符流
            template.process(data, out);
            out.flush();
            return out.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }
}
